/* 
 * File:   SMUManager.h
 * Author: Vicky.H
 * Email:  eclipser@163.com
 *
 * Created on 2014年1月16日, 下午10:40
 */

#ifndef CN_VICKY__SMUMANAGER_H
#define	CN_VICKY__SMUMANAGER_H

#include "ShareMemAO.h"
#include "Common.h"
#include "Log.h"

#include "string.h"

// 全局CMD参数

extern int g_CmdArgv;

// 共享内存池类型

enum SMPOOL_TYPE {
    SMPT_SHAREMEM, // 
    SMPT_SERVER, // 服务器使用的共享内存池
    SMPT_WORLD, // 世界服务器使用的共享内存池
};


//ShareMemory 单元池

template<typename T> // T 类型需要包涵成员函数：SetPoolID(uint index)，
                        // 并且能通过sizeof(T) 获得其所一个对象最大所占空间。
                        // 故最好包涵SMUHead属性。
class SMUPool {
public:

    SMUPool() : m_pRefObjPtr(), m_hObj(), m_nMaxSize(-1), m_nPosition(-1) {
    }

    ~SMUPool() {
        __ENTER_FUNCTION

        SAFE_DELETE(m_pRefObjPtr);
        SAFE_DELETE_ARRAY(m_hObj);

        __LEAVE_FUNCTION
    }

    // 初始化共享内存单元池,分配key，大小为nMaxCount * sizeof(T) + sizeof(SMHead) 的共享内存区
    bool Init(uint nMaxCount /*初始化数量*/, SM_KEY key /*标识*/, SMPOOL_TYPE SMPT /*共享内存区类型*/) {
        __ENTER_FUNCTION
        // 创建共享内存对象
        m_pRefObjPtr = new ShareMemAO();
        Assert(m_pRefObjPtr);
        if (!m_pRefObjPtr)
            return false;
        // 设置为全局命令模式
        m_pRefObjPtr->m_CmdArg = g_CmdArgv;
        bool ret;
        
        // 打开共享内存区
        ret = m_pRefObjPtr->Attach(key, sizeof (T) * nMaxCount + sizeof (SMHead));
        if (SMPT == SMPT_SHAREMEM) {
            if (!ret) {
                // 打开失败，但类型如果是共SMPT_SHAREMEM，那么新建共享内存区
                ret = m_pRefObjPtr->Create(key, sizeof (T) * nMaxCount + sizeof (SMHead));
            }
        } else {
            if (!ret) {
                return false;
            }
        }

        if (!ret) {
            // 如果打开失败，设置命令为删除
            if (m_pRefObjPtr->m_CmdArg == CMD_MODE_CLEARALL) {
                return true;
            }
            Log::SaveLog(SHMEM_LOG_PATH, "Setup SMU block fail!");
            Assert(ret);
            return ret;

        }

        m_nMaxSize = nMaxCount;
        m_nPosition = 0;
        // 创建指向内存池所有T空间的数组
        m_hObj = new T* [m_nMaxSize];

        int i;
        for (i = 0; i < m_nMaxSize; i++) {
            // 初始化数组值
            m_hObj[i] = reinterpret_cast<T*> (m_pRefObjPtr->GetTypePtr(sizeof (T), i));
            if (m_hObj[i] == NULL) {
                Assert(m_hObj[i] != NULL);
                return false;
            }
        }

        m_key = key;

        return true;
        __LEAVE_FUNCTION
        return false;
    }

    // 结束，销毁共享内存区
    bool Finalize() {
        __ENTER_FUNCTION

        Assert(m_pRefObjPtr);
        m_pRefObjPtr->Destory();
        return true;

        __LEAVE_FUNCTION

        return false;

    }

    // 通过内存池
    T* NewObj(void) {
        __ENTER_FUNCTION

        Assert(m_nPosition < m_nMaxSize);
        if (m_nPosition >= m_nMaxSize) {
            return NULL;
        }

        T *pObj = m_hObj[m_nPosition];
        // 设置对象在内存池的坐标
        pObj->SetPoolID((uint) m_nPosition);
        // 每分配一个内存单元后，坐标+1
        m_nPosition++;
        return pObj;
        __LEAVE_FUNCTION
        return NULL;
    }

    // 释放内存单元，可重新使用该内存区。
    void DeleteObj(T *pObj) {
        __ENTER_FUNCTION

        Assert(pObj != NULL);
        if (pObj == NULL) {
            return;
        }
        Assert(m_nPosition > 0);
        if (m_nPosition <= 0) {
            return;
        }
        uint uDelIndex = pObj->GetPoolID();
        Assert(uDelIndex < (uint) m_nPosition);
        if (uDelIndex >= (uint) m_nPosition) {
            return;
        }
        // 将被释放的内存区与内存池最后一个坐标指针交换，设置当前坐标-1
        m_nPosition--;
        T *pDelObj = m_hObj[uDelIndex];
        m_hObj[uDelIndex] = m_hObj[m_nPosition];
        m_hObj[m_nPosition] = pDelObj;

        m_hObj[uDelIndex]->SetPoolID(uDelIndex);
        m_hObj[m_nPosition]->SetPoolID(INVALID_ID); // 设置该内存单元的坐标无效，
        // 表示尚未被使用，可以通过NewObj() 获得
        __LEAVE_FUNCTION
    }

    // 获得共享内存池指定区
    T* GetPoolObj(int iIndex) {
        Assert(iIndex < m_nMaxSize);
        return m_hObj[iIndex];
    }

    // 获得共享内存池大小
    int GetPoolMaxSize() {
        return m_nMaxSize;
    }

    // 获得已经使用的大小
    int GetPoolSize() {
        return m_nPosition;
    }

    // 获得共享内存区的key
    SM_KEY GetKey() {
        return m_key;
    }

    // 将共享内存区的数据备份到文件中
    bool DumpToFile(char* FilePath) {
        if (!m_pRefObjPtr) {
            Assert(m_pRefObjPtr);
            return false;
        }

        return m_pRefObjPtr->DumpToFile(FilePath);
    }

    // 将文件数据，加载到共享内存区中
    bool MergeFromFile(char* FilePath) {
        if (!m_pRefObjPtr) {
            Assert(m_pRefObjPtr);
            return false;
        }
        return m_pRefObjPtr->MergeFromFile(FilePath);
    }

    // 获得版本号
    uint GetHeadVer() {
        Assert(m_pRefObjPtr);
        return m_pRefObjPtr->GetHeadVer();
    }

    // 设置版本号
    void SetHeadVer(uint ver) {
        Assert(m_pRefObjPtr);
        return m_pRefObjPtr->SetHeadVer(ver);
    }


private:
    T** m_hObj; //管理对象SMU数组，new T* [m_nMaxSize]
    int m_nMaxSize; //最大容量，存放T的个数
    int m_nPosition; //当前使用偏移
    ShareMemAO* m_pRefObjPtr; //引用SMObject，操作类对象
    SM_KEY m_key; //对应的ShareMemory Key
};

#define SM_USE_FREE			0
#define SM_USE_READYFREE		1
#define SM_USE_FREEED			2
#define SM_USE_HOLDDATA			3

#define		SM_FREE					0x00	//共享内存空闲
#define		SM_C_READ				0x01	//共享内存自己读取
#define		SM_C_WRITE				0x02	//共享内存自己写
#define		SM_S_READ				0x03	//Server读
#define		SM_S_WRITE				0x04	//Server写
#define		SM_W_READ				0x05	//World 读
#define		SM_W_WRITE				0x06	//World 写

struct SMUHead {
    uint PoolId;
    SMUID_t SMUid;
    int UseStatus;
    char flag;
    short PID;
    uint SaveTime; //应该是保存绝对时间，
    //因为牵涉到不同进程之间通讯
    //精确到秒

    SMUHead() {
        CleanUp();
    }

    void CleanUp() {
        PoolId = -1;
        SMUid = 0;
        PID = -1;
        UseStatus = SM_USE_FREE;
        flag = SM_FREE;
        SaveTime = 0;
    }

}; 

#endif	/* CN_VICKY__SMUMANAGER_H */

